﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Pavilion;

namespace Pavilion.GameTools
{
    public class AnimationTool : GameToolBase
    {
        private static Dictionary<string, Action<AnimationTool, object>> dataExecutionDictionary;

        public event Action<Animation> AnimationComplete;
        public event Action<AnimationNode> AnimationNodeLoaded, AnimationNodeUnloaded;

        public List<NodeMonitorAnimationPlayer> AnimationPlayerList { get; private set; }
        public bool Reverse { set { SetIsReverse(value); } }

        private NodeTool nodeTool;
        private float size;

        public AnimationTool(GameItem parentGameItem) : base(parentGameItem)
        {
            AnimationPlayerList = new List<NodeMonitorAnimationPlayer>();
            LoadDataExecution();
        }

        public override void Dispose()
        {
            ParentGameItem.UpdateLogic -= ParentGameItem_UpdateLogic;

            foreach (NodeMonitorAnimationPlayer animationPlayer in AnimationPlayerList)
                animationPlayer.Dispose();

            AnimationPlayerList.Clear();

            base.Dispose();
        }

        private void LoadDataExecution()
        {
            if (dataExecutionDictionary != null)
                return;

            dataExecutionDictionary = new Dictionary<string, Action<AnimationTool, object>>();

            dataExecutionDictionary.Add("Reverse", (animationTool, value) => animationTool.Reverse = (bool)value);
        }

        public override void UpdateProperty(string propertyName, object propertyValue)
        {
            dataExecutionDictionary[propertyName].Invoke(this, propertyValue);
        }

        public override void Load()
        {
            nodeTool = ParentGameItem.ObtainTool<NodeTool>();
            nodeTool.NodeMonitorAdded += (nodeScript, nodeMonitor) => AddNodeMonitor(nodeScript, nodeMonitor);
            nodeTool.NodeMonitorRemoved += (nodeScript, nodeMonitor) => AddNodeMonitor(nodeScript, nodeMonitor);

            foreach (KeyValuePair<NodeScript, ContainerNodeMonitor> item in nodeTool.ContainerNodeMonitorCollection)
                AddNodeMonitor(item.Key, item.Value);

            ParentGameItem.UpdateLogic += ParentGameItem_UpdateLogic;
        }

        public void Draw(Vector2 position, float size, Vector2 origin, SpriteEffects spriteEffect)
        {
            this.size = size;

            foreach (NodeMonitorAnimationPlayer animationPlayer in AnimationPlayerList)
                animationPlayer.Draw(position, size, origin, spriteEffect);
        }

        public void UpdateCurrentAnimation()
        {
            foreach (NodeMonitorAnimationPlayer animationPlayer in AnimationPlayerList)
                animationPlayer.UpdateCurrentAnimation();
        }

        private void AddNodeMonitor(NodeScript nodeScript, ContainerNodeMonitor nodeMonitor)
        {
            if (nodeScript.NodeScriptType == NodeScriptType.Animation || nodeScript.NodeScriptType == NodeScriptType.Mix)
            {
                var animationPlayer = new NodeMonitorAnimationPlayer(nodeMonitor);
                animationPlayer.AnimationNodeLoaded += OnAnimationNodeLoaded;
                animationPlayer.AnimationNodeUnloaded += OnAnimationNodeUnloaded;
                animationPlayer.Complete += OnAnimationComplete;
                AnimationPlayerList.Add(animationPlayer);
            }
        }

        private void RemoveNodeMonitor(NodeScript nodeScript, ContainerNodeMonitor nodeMonitor)
        {
            NodeMonitorAnimationPlayer animationPlayer = AnimationPlayerList.First(x => x.NodeMonitor == nodeMonitor);

            AnimationPlayerList.Remove(animationPlayer);
            animationPlayer.Dispose();
        }

        private void SetIsReverse(bool isReverse)
        {
            foreach (AnimationPlayer animationPlayer in AnimationPlayerList)
                animationPlayer.IsReverse = isReverse;
        }

        private void OnAnimationComplete(Animation animation)
        {
            if (AnimationComplete != null)
                AnimationComplete(animation);
        }

        private void OnAnimationNodeUnloaded(AnimationNode node)
        {
            if (AnimationNodeUnloaded != null)
                AnimationNodeUnloaded(node);
        }

        private void OnAnimationNodeLoaded(AnimationNode node)
        {
            if (AnimationNodeLoaded != null)
                AnimationNodeLoaded(node);
        }

        private void ParentGameItem_UpdateLogic(GameTime gameTime)
        {
            foreach (NodeMonitorAnimationPlayer animationPlayer in AnimationPlayerList)
                animationPlayer.Animate(gameTime, size);
        }

        static public void PauseAnimationTools()
        {
            foreach (Pavilion.GameTools.AnimationTool animationTool in GameItemManager.Instance.GetToolsFromGameItems<Pavilion.GameTools.AnimationTool>())
            {
                foreach (var animationPlayer in animationTool.AnimationPlayerList)
                    animationPlayer.NodeMonitor.Pause();
            }
        }

        static public void ResumeAnimationTools()
        {
            foreach (Pavilion.GameTools.AnimationTool animationTool in GameItemManager.Instance.GetToolsFromGameItems<Pavilion.GameTools.AnimationTool>())
            {
                foreach (var animationPlayer in animationTool.AnimationPlayerList)
                    animationPlayer.NodeMonitor.Resume();
            }
        }
    }
}
